local KBLib = {};

local match = string.match;
local gsub = string.gsub;

function KBLib:ProcessClick(group, button, ...)
	local potentials = self:Get("keybindings", group);
	if potentials then
		local num;
		if button == "LeftButton" then num = "1";
		elseif button == "RightButton" then num = "2";
		elseif button == "MiddleButton" then num = "3";
		else num = match(button, "(%d+)");
		end
		if not num then return end
        
		local modifierstate = self:GetModifierState();
		for i,v in pairs(potentials) do
			local modifiers, mouse = match(v, "(.-)-?(%d+)$");
			if mouse == num and modifiers == modifierstate then 
				self:PerformClickAction(group, i, ...);
				break;
			end
		end
	end
end

local states = {
	["000"] = "",
	["100"] = "s",
	["010"] = "c",
	["001"] = "a",
	["110"] = "s-c",
	["101"] = "s-a",
	["011"] = "c-a",
	["111"] = "s-c-a",
}
function KBLib:GetModifierState()
	return states[(IsShiftKeyDown() and "1" or "0")..(IsControlKeyDown() and "1" or "0")..(IsAltKeyDown() and "1" or "0")];
end

function KBLib:SetClickAction(group, action, func)
    local kblib = self.libraries["KBLib"];
    kblib.actions = kblib.actions or {};
    kblib.actions[group] = kblib.actions[group] or kblib.actions[group] or {};
    kblib.actions[group][action] = func;
end

function KBLib:PerformClickAction(group, action, ...)
	local kblib = self.libraries["KBLib"];
	if kblib.actions and kblib.actions[group] and kblib.actions[group][action] then
		kblib.actions[group][action](...);
	end
end

local subFunc = function(a)
    if a == "s-" then return "Shift-"; end
    if a == "c-" then return "Control-"; end
    if a == "a-" then return "Alt-"; end
    if a == "1" then return "Left Click"; end
    if a == "2" then return "Right Click"; end
    if a == "3" then return "Middle Click"; end
end
function KBLib:GetKeyBinding(group, action)
	local kb = self:Get("keybindings",group,action);
	kb = string.gsub(kb, "%a%-", subFunc);
    kb = string.gsub(kb, "%d", subFunc);
	return kb;
end

local group,action,mouse,isshift,isalt,isctrl

local function kbclickfunc(self)
	local level = UIDROPDOWNMENU_MENU_LEVEL;
	local str = ""
	if isshift then str = str.."s-" end
	if isctrl then str = str.."c-" end
	if isalt then str = str.."a-" end
	str = str..mouse
	local otheractions = self:Get("keybindings",group)
	for act,kb in pairs(otheractions) do
		if not (action == act) then
			if kb == str then
				self:HeaderPrint("Unable to set keybinding (another action is already using it).")
				return
			end
		end
	end
	self:Set("keybindings", group, action, str)
	CloseDropDownMenus()
end

function KBLib:KBDropDown()
	local info
	if UIDROPDOWNMENU_MENU_LEVEL == 6 or UIDROPDOWNMENU_MENU_LEVEL == 7 or UIDROPDOWNMENU_MENU_LEVEL == 8 then
		local value = UIDROPDOWNMENU_MENU_LEVEL - 1
		if (isshift or 0) >= value then isshift = nil end
		if (isctrl or 0) >= value then isctrl = nil end
		if (isalt or 0) >= value then isalt = nil end
		if UIDROPDOWNMENU_MENU_VALUE == "shift" then isshift = value
		elseif UIDROPDOWNMENU_MENU_VALUE == "alt" then isalt = value
		elseif UIDROPDOWNMENU_MENU_VALUE == "ctrl" then isctrl = value
		end
		if not isshift then
			info = UIDropDownMenu_CreateInfo()
			info.text = "Shift"
			info.value = "shift"
			info.hasArrow = (UIDROPDOWNMENU_MENU_LEVEL == 8 and nil or 1)
			info.notCheckable = 1
			info.func = function() isshift = UIDROPDOWNMENU_MENU_VALUE kbclickfunc(self) end
			UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL)
		end
		if not isctrl then
			info = UIDropDownMenu_CreateInfo()
			info.text = "Control"
			info.value = "ctrl"
			info.hasArrow = (UIDROPDOWNMENU_MENU_LEVEL == 8 and nil or 1)
			info.notCheckable = 1
			info.func = function() isctrl = UIDROPDOWNMENU_MENU_VALUE kbclickfunc(self) end
			UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL)
		end
		if not isalt then
			info = UIDropDownMenu_CreateInfo()
			info.text = "Alt"
			info.value = "alt"
			info.hasArrow = (UIDROPDOWNMENU_MENU_LEVEL == 8 and nil or 1)
			info.notCheckable = 1
			info.func = function() isalt = UIDROPDOWNMENU_MENU_VALUE kbclickfunc(self) end
			UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL)
		end
	elseif UIDROPDOWNMENU_MENU_LEVEL == 5 then
		local value = UIDROPDOWNMENU_MENU_LEVEL - 1
		if (isshift or 0) >= value then isshift = nil end
		if (isctrl or 0) >= value then isctrl = nil end
		if (isalt or 0) >= value then isalt = nil end
		mouse = UIDROPDOWNMENU_MENU_VALUE
		info = UIDropDownMenu_CreateInfo()
		info.text = "Shift"
		info.value = "shift"
		info.hasArrow = 1
		info.notCheckable = 1
		info.func = function() isshift = 5 kbclickfunc(self) end
		UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL)
		info = UIDropDownMenu_CreateInfo()
		info.text = "Control"
		info.value = "ctrl"
		info.hasArrow = 1
		info.notCheckable = 1
		info.func = function() isctrl = 5 kbclickfunc(self) end
		UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL)
		info = UIDropDownMenu_CreateInfo()
		info.text = "Alt"
		info.value = "alt"
		info.hasArrow = 1
		info.notCheckable = 1
		info.func = function() isalt = 5 kbclickfunc(self) end
		UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL)
	elseif UIDROPDOWNMENU_MENU_LEVEL == 4 then
		isshift,isctrl,isalt = nil,nil,nil
		info = UIDropDownMenu_CreateInfo()
		info.text = "Left Click"
		info.value = 1
		info.hasArrow = 1
		info.notCheckable = 1
		info.func = function() mouse = 1 kbclickfunc(self) end
		UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL)
		info = UIDropDownMenu_CreateInfo()
		info.text = "Right Click"
		info.value = 2
		info.hasArrow = 1
		info.notCheckable = 1
		info.func = function() mouse = 2 kbclickfunc(self) end
		UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL)
		info = UIDropDownMenu_CreateInfo()
		info.text = "Middle Click"
		info.value = 1
		info.hasArrow = 1
		info.notCheckable = 1
		info.func = function() mouse = 3 kbclickfunc(self) end
		UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL)
	elseif UIDROPDOWNMENU_MENU_LEVEL == 3 then
		action = UIDROPDOWNMENU_MENU_VALUE
		info = UIDropDownMenu_CreateInfo()
		info.text = "Current Keybinding"
		info.notCheckable = 1
		info.isTitle = 1
		UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL)
		info = UIDropDownMenu_CreateInfo()
		info.text = self:GetKeyBinding(group,action)
		info.notClickable = 1
		info.notCheckable = 1
		UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL)
		info = UIDropDownMenu_CreateInfo()
		info.text = ""
		info.notClickable = 1
		UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL)
		info = UIDropDownMenu_CreateInfo()
		info.text = "Change Keybinding"
		info.hasArrow = 1
		info.notCheckable = 1
		UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL)
	elseif UIDROPDOWNMENU_MENU_LEVEL == 2 then
		group = UIDROPDOWNMENU_MENU_VALUE
		local actions = self:Get("keybindings",group)
		for i,v in pairs(actions) do
			info = UIDropDownMenu_CreateInfo()
			info.text = i
			info.hasArrow = 1
			info.notCheckable = 1
			info.value = i
			UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL)
		end
	elseif UIDROPDOWNMENU_MENU_LEVEL == 1 then
		local groups = self:Get("keybindings")
		for i,v in pairs(groups) do
			info = UIDropDownMenu_CreateInfo()
			info.notCheckable = 1
			info.text = i
			info.value = i
			info.hasArrow = 1
			UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL)
		end
	end
end

AsheylaLib:CreateLibrary("KBLib", KBLib);
